﻿Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework

Public Class GamePadInputManager
    Implements IGamePadInputManager

    Private mKeys As Dictionary(Of GamePadKeys, Buttons) = New Dictionary(Of GamePadKeys, Buttons)
    Private mPreviousState As GamePadState
    Private mCurrentState As GamePadState
    Private mPlayerIndex As PlayerIndex
    Private mInvertYAxis As Boolean

    Public Sub New(Optional ByVal playerIndex As PlayerIndex = PlayerIndex.One, Optional ByVal invertYAxis As Boolean = False)
        mPlayerIndex = Microsoft.Xna.Framework.PlayerIndex.One
        mInvertYAxis = invertYAxis

        ' Default Key Mapping
        With mKeys

            .Add(GamePadKeys.MainMovementUp, Buttons.LeftThumbstickUp)
            .Add(GamePadKeys.MainMovementDown, Buttons.LeftThumbstickDown)
            .Add(GamePadKeys.MainMovementLeft, Buttons.LeftThumbstickLeft)
            .Add(GamePadKeys.MainMovementRight, Buttons.LeftThumbstickRight)
            .Add(GamePadKeys.MainSelect, Buttons.LeftStick)

            .Add(GamePadKeys.SecondaryMovementUp, Buttons.RightThumbstickUp)
            .Add(GamePadKeys.SecondaryMovementDown, Buttons.RightThumbstickDown)
            .Add(GamePadKeys.SecondaryMovementLeft, Buttons.RightThumbstickLeft)
            .Add(GamePadKeys.SecondaryMovementRight, Buttons.RightThumbstickRight)
            .Add(GamePadKeys.SecondarySelect, Buttons.RightStick)

            .Add(GamePadKeys.LeftShoulder, Buttons.LeftShoulder)
            .Add(GamePadKeys.RightShoulder, Buttons.RightShoulder)

            .Add(GamePadKeys.Back, Buttons.Back)
            .Add(GamePadKeys.Start, Buttons.Start)
            .Add(GamePadKeys.A, Buttons.A)
            .Add(GamePadKeys.B, Buttons.B)
            .Add(GamePadKeys.X, Buttons.X)
            .Add(GamePadKeys.Y, Buttons.Y)

        End With
    End Sub

    Public Function A() As Boolean Implements IGamePadInputManager.APressed
        Return IsNewKeypress(Buttons.A)
    End Function

    Public Function B() As Boolean Implements IGamePadInputManager.BPressed
        Return IsNewKeypress(Buttons.B)
    End Function

    Public Function Back() As Boolean Implements IGamePadInputManager.BackPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.Back))
    End Function

    Public Function LeftShoulder() As Boolean Implements IGamePadInputManager.LeftShoulderPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.LeftShoulder))
    End Function

    Public Function LeftTrigger() As Single Implements IGamePadInputManager.LeftTrigger
        Return mCurrentState.Triggers.Left
    End Function

    Public Function MainMovement() As Microsoft.Xna.Framework.Vector2 Implements IGamePadInputManager.MainMovement
        MainMovement = mCurrentState.ThumbSticks.Left
        If mInvertYAxis Then
            MainMovement.Y *= -1 ' TODO - only do this if GamerProfile.InvertYAxis
        End If
    End Function

    Public Function MainSelect() As Boolean Implements IGamePadInputManager.MainSelectPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.MainSelect))
    End Function

    Public Function RightShoulder() As Boolean Implements IGamePadInputManager.RightShoulderPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.RightShoulder))
    End Function

    Public Function RightTrigger() As Single Implements IGamePadInputManager.RightTrigger
        Return mCurrentState.Triggers.Right
    End Function

    Public Function SecondaryMovement() As Microsoft.Xna.Framework.Vector2 Implements IGamePadInputManager.SecondaryMovement
        Return mCurrentState.ThumbSticks.Right
    End Function

    Public Function SecondarySelect() As Boolean Implements IGamePadInputManager.SecondarySelectPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.SecondarySelect))
    End Function

    Public Function Start() As Boolean Implements IGamePadInputManager.StartPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.Start))
    End Function

    Public Function X() As Boolean Implements IGamePadInputManager.XPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.X))
    End Function

    Public Function Y() As Boolean Implements IGamePadInputManager.YPressed
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.Y))
    End Function

    Public Function MenuMainMovement() As Microsoft.Xna.Framework.Vector2 Implements IGamePadInputManager.MenuMainMovement
        ' Main Movement (Left Thumbstick) takes precidence over DPad
        MenuMainMovement = MainMovement()
        If MenuMainMovement.X = 0 And MenuMainMovement.Y = 0 Then
            MenuMainMovement = MenuMovement()
        End If
    End Function

    Public Function MenuMovement() As Microsoft.Xna.Framework.Vector2 Implements IGamePadInputManager.MenuMovement
        Dim UpDown As Single = 0.0F
        Dim LeftRight As Single = 0.0F

        With mCurrentState
            If .IsButtonDown(Buttons.DPadUp) Then
                UpDown = -1.0F
            ElseIf .IsButtonDown(Buttons.DPadDown) Then
                UpDown = 1.0F
            End If
            If .IsButtonDown(Buttons.DPadLeft) Then
                LeftRight = -1.0F
            ElseIf .IsButtonDown(Buttons.DPadRight) Then
                LeftRight = 1.0F
            End If
        End With

        Return New Vector2(LeftRight, UpDown)

    End Function

    Private Function IsNewKeypress(ByVal button As Buttons) As Boolean
        Return mCurrentState.IsButtonDown(button) AndAlso Not mPreviousState.IsButtonDown(button)
    End Function

    Public Sub Update(ByVal elapsedTime As Single) Implements IGamePadInputManager.Update
        mPreviousState = mCurrentState
        mCurrentState = GamePad.GetState(mPlayerIndex)
    End Sub

    Public Function ADown() As Boolean Implements IGamePadInputManager.ADown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.A))
    End Function

    Public Function BackDown() As Boolean Implements IGamePadInputManager.BackDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.Back))
    End Function

    Public Function BDown() As Boolean Implements IGamePadInputManager.BDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.B))
    End Function

    Public Function LeftShoulderDown() As Boolean Implements IGamePadInputManager.LeftShoulderDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.LeftShoulder))
    End Function

    Public Function MainSelectDown() As Boolean Implements IGamePadInputManager.MainSelectDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.MainSelect))
    End Function

    Public Function RightShoulderDown() As Boolean Implements IGamePadInputManager.RightShoulderDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.RightShoulder))
    End Function

    Public Function SecondarySelectDown() As Boolean Implements IGamePadInputManager.SecondarySelectDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.SecondarySelect))
    End Function

    Public Function StartDown() As Boolean Implements IGamePadInputManager.StartDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.Start))
    End Function

    Public Function XDown() As Boolean Implements IGamePadInputManager.XDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.X))
    End Function

    Public Function YDown() As Boolean Implements IGamePadInputManager.YDown
        Return mCurrentState.IsButtonDown(mKeys(GamePadKeys.Y))
    End Function

    Public Function Down(ByVal name As String) As Boolean Implements IInputManager.Down
        Dim key As GamePadKeys

        If [Enum].TryParse(Of GamePadKeys)(name, True, key) Then
            Return mCurrentState.IsButtonDown(mKeys(key))
        Else
            Return False
        End If
    End Function

    Public Function Movement(ByVal name As String) As Microsoft.Xna.Framework.Vector2 Implements IInputManager.Movement
        Select Case name
            Case cnstMainMovement
                Return MainMovement()
            Case cnstSecondaryMovement
                Return SecondaryMovement()
            Case cnstRightThumbStick
                Return SecondaryMovement()
            Case cnstLeftThumbStick
                Return MainMovement()
            Case Else
                Return Vector2.Zero
        End Select
    End Function

    Public Function Position(ByVal name As String) As Microsoft.Xna.Framework.Vector3 Implements IInputManager.Position
        Return Vector3.Zero
    End Function

    Public Function Pressed(ByVal name As String) As Boolean Implements IInputManager.Pressed
        Dim key As GamePadKeys

        If [Enum].TryParse(Of GamePadKeys)(name, True, key) Then
            Return IsNewKeypress(mKeys(key))
        Else
            Return False
        End If
    End Function

    Public Function Value(ByVal name As String) As Single Implements IInputManager.Value
        Select Case name
            Case cnstRightTrigger
                Return RightTrigger()
            Case cnstLeftTrigger
                Return LeftTrigger()
            Case Else
                Return String.Empty
        End Select
    End Function

End Class